#include <iostream>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <unistd.h>
#include <strings.h>
#include <memory>
#include <cstring>
#include "log.hpp"
#include <functional>
#include <stdio.h>
#include <vector>
#include<unordered_map>

using c_back = function<string(string info)>;

class udpserver
{
public:
    udpserver(const uint16_t &port, const string &ip = "0.0.0.0")
        : _ip(ip), _port(port), _isrunning(false)
    {
        init();
    }
    ~udpserver()
    {
        close(_fd);
    }

    void init()
    {
        _fd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_fd == -1)
        {
            log(ERROR, "open socket fail!");
            cout << "error: " << strerror(errno) << endl;
            exit(-1);
        }

        log(NOTICE, "socket create success!");

        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_addr.s_addr = inet_addr(_ip.c_str());
        local.sin_port = htons(_port);

        int ret = bind(_fd, (const struct sockaddr *)&local, sizeof(local));
        if (ret == -1)
        {
            log(ERROR, "bind fail!");
            cout << "error: " << strerror(errno) << endl;
            exit(-1);
        }
        log(NOTICE, "bind success!");
    }

    void welecom(string usertIp, const sockaddr_in& client,uint16_t userPort)
    {
        //log(DEBUG,"line 62 server.cpp");
        if(_user_tb.find(usertIp)==_user_tb.end())
        {
            _user_tb.insert(make_pair(usertIp,client));
            cout<<"["<<usertIp<<":"<<userPort<<"] "<<"welecome new user!"<<endl;
        }
    }

    void transmit(string info)
    {

        for(auto u:_user_tb)
        {
            int n = sendto(_fd, info.c_str(), info.size(), 0, (const struct sockaddr *)(&u.second),sizeof(u.second));
            if (n == -1)
            {
                log(WARNING, "sendto fail!");
            }
        }
    }

    string dealMsg(const string& info,string userIp,uint16_t userPort)
    {
        string result;
        result="["+userIp+":"+to_string(userPort)+"]: "+info;
        //cout<<result<<endl;
        return result;
    }

    void run()
    {
        _isrunning = true;
        struct sockaddr_in client;
        socklen_t len = sizeof(client);
        while (_isrunning)
        {
            char buffer[1024]={0};
            // 获取数据(可以看作消费者消费数据)
            int n = recvfrom(_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&client, &len);
            if (n == -1)
            {
                log(WARNING, "recvfrom fail!");
            }
            buffer[n] = '\0';

            // 下面对数据进行处理
            uint16_t userPort = ntohs(client.sin_port);
            char addr_buffer[1024] = {0};
            inet_ntop(AF_INET, &client.sin_addr, addr_buffer, sizeof(buffer));
            string userIp=addr_buffer;
            welecom(userIp,client,userPort);

            string info = dealMsg(buffer,userIp,userPort);
            


            // 下面将数据返回给客户端(看作生产者生产数据)
            transmit(info);
        }
    }

private:
    int _fd;
    string _ip;
    uint16_t _port;
    bool _isrunning;
    unordered_map<string,sockaddr_in> _user_tb;
};